import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { NestExpressApplication } from '@nestjs/platform-express';
import { ConfigService } from '@nestjs/config';
import { ValidationPipe } from '@nestjs/common';
import { knife4jSetup } from 'nestjs-knife4j2';

import rateLimit from 'express-rate-limit';
// import helmet from 'helmet'; // 是一个用于增强Express应用安全性的中间件集合。它通过设置各种HTTP响应头来帮助保护应用免受常见的Web安全威胁，如跨站脚本攻击（XSS）、点击劫持等‌
import { AppModule } from './app.module';
import { mw as requestIpMw } from 'request-ip';

import { HttpExceptionFilter } from '@/common/filters/http.exception.filter';

import { join } from 'path';
import { writeFileSync } from 'fs';
import { RequestIdInterceptor } from '@/common/interceptors/request-id.interceptor';
import { CommonMiddleware } from '@/common/middlewares/common.middleware';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule, {
    cors: true, // 开启跨域访问
  });
  const config = app.get(ConfigService);
  // 设置 api 访问前缀
  const prefix = config.get<string>('app.prefix');
  const rootPath = process.cwd();
  const baseDirPath = join(rootPath, config.get('app.file.location'));
  app.useStaticAssets(baseDirPath, {
    prefix: '/profile/',
    maxAge: 86400000 * 365,
  });
  app.setGlobalPrefix(prefix);

  // 1.中间件
  app.use(
    rateLimit({
      windowMs: 15 * 60 * 1000, // 15分钟
      max: 1000, // 限制15分钟内最多只能访问1000次
    }),
  ); // 设置访问频率
  // eslint-disable-next-line @typescript-eslint/unbound-method
  app.use(new CommonMiddleware().use);
  app.use(requestIpMw({ attributeName: 'ip' })); // 获取真实 ip

  // 2.守卫

  // 3.全局拦截器
  app.useGlobalInterceptors(new RequestIdInterceptor());

  // 4。管道

  // 5.全局过滤器
  app.useGlobalFilters(new HttpExceptionFilter());

  // web 安全，防常见漏洞
  // 注意： 开发环境如果开启 nest static module 需要将 crossOriginResourcePolicy 设置为 false 否则 静态资源 跨域不可访问
  // app.use(
  //   helmet({ crossOriginOpenerPolicy: { policy: 'same-origin-allow-popups' }, crossOriginResourcePolicy: false }),
  // );

  // 全局验证
  app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }));

  const swaggerOptions = new DocumentBuilder()
    .setTitle('nestjs 常规后台模版')
    .setDescription('nestjs 常规后台模版-接口文档')
    .setVersion('2.0.0')
    .addBearerAuth(
      {
        type: 'http',
        scheme: 'bearer',
        bearerFormat: 'JWT',
      },
      'token',
    )
    .build();
  const document = SwaggerModule.createDocument(app, swaggerOptions);
  // 保存OpenAPI规范文件
  writeFileSync(join(process.cwd(), 'openApi.json'), JSON.stringify(document, null, 2));

  const swaggerDocPrefix = `${prefix}/api/swagger-ui`;

  // 项目依赖当前文档功能，最好不要改变当前地址
  // 生产环境使用 nginx 可以将当前文档地址 屏蔽外部访问
  SwaggerModule.setup(swaggerDocPrefix, app, document, {
    swaggerOptions: {
      persistAuthorization: true,
    },
  });
  knife4jSetup(app, [
    {
      name: '2.0 version',
      url: `${swaggerDocPrefix}-json`,
      swaggerVersion: '2.0',
      location: `${swaggerDocPrefix}-json`,
    },
  ]);

  //服务端口
  const port = config.get<number>('app.port') || 8080;
  await app.listen(port);

  console.log(
    `Nest-Admin 服务启动成功`,
    '\n',
    '服务地址',
    `http://localhost:${port}${prefix}/`,
    '\n',
    'swagger 文档地址',
    `http://localhost:${port}${prefix}/swagger-ui/`,
  );
}

void bootstrap();
